-------------Un Dia Tipico-------------
A 4am crack                  2014-07-21
-------------------. updated 2024-10-06
                   |___________________

"Un Dia Tipico" is a 1985 educational
game distributed by D.C. Heath & Co.
Despite the name, the program is
primarily in English.

The original program comes on three
single-sided disks. Disk 1 boots, loads
DOS, displays a (slightly delayed)
BASIC prompt, then runs a HELLO program
of some sort. Disk 2 and 3 simply boot
to a text message saying "INSERT DISK 1
AND PRESS ANY KEY".

COPYA fails miserably and immediately
with a disk read error. EDD 4 bit copy
gives no read errors, but the copy
grinds the disk drive on boot and never
gets any further.

Turning to my trusty Copy ][+ sector
editor, I can read track 0 and every
even track without any problem. But the
odd-numbered tracks are opaque. If I
switch to the nibble editor, it appears
that the odd-numbered tracks use a
non-standard address prologue, "D4 AA
96" instead of the usual "D5 AA 96".

[S6,D1=original disk]
[S5,D1=my work disk]

]PR#5
CAPTURING BOOT0
...reboots slot 6...
...reboots slot 5...
SAVING BOOT0

For those of you just tuning in, my
work disk uses a custom program that I
affectionately call "AUTOTRACE" to
automate the process of boot tracing as
far as possible. For some disks (like
this one, apparently), it just captures
track 0, sector 0 (saved in a file
called "BOOT0") and stops. For other
disks that load in the same way that an
unprotected DOS 3.3 disk loads, it
captures the next stage of the boot
process as well (in a file called
"BOOT1"). BOOT1 contains sectors 0-9 on
track 0, which are loaded into memory
at $B600..$BFFF. This generally
contains the RWTS routines which the
program uses to read the rest of the
disk.

If the RWTS is fairly normal as well
(and my AUTOTRACE program just spot-
checks a few memory locations to guess
at its "normalcy"), AUTOTRACE extracts
the RWTS routines (generally loaded
from track 0, sectors 2-9 into $B800..
$BFFF) and saves *that* into a third
file called "RWTS". There's a good
chance I'll be able to load that "RWTS"
file into a tool called Advanced
Demuffin (written in 1983 by The Stack)
to convert the disk into a standard
disk readable by unprotected DOS 3.3
disks or any other third-party tools.

If anything looks fishy or non-
standard, AUTOTRACE just stops, and I
have to check the files it saved so far
to determine why. In this case, it
stopped after capturing T00,S00. So I
need to look at that sector and figure
out why.

]CALL -151

*800<2800.28FFM

*801L
...

I've seen a lot of boot0 code from
different copy-protected (and not
copy-protected) disks, so I've kind of
developed a sense of what a "normal"
boot looks like. I can look at almost-
but-not-quite normal boot0 code and
hone in pretty quickly on the part
that's unusual. Maybe it calls a
subroutine that isn't normally called,
or it does things in a strange order,
or it jumps to an unusual place after
loading the boot1 code.

Everything here looks pretty normal
(i.e. just like an unprotected DOS 3.3
disk), until it goes to jump to the
boot1 code. Usually that happens with
an indirect JMP ($08FD), which, in a
normal boot0, will end up continuing
execution at $B700 which is stored in
track 0, sector 1. But in this case, I
see:

084A-   4C 00 BB    JMP   $BB00

Highly suspect. I definitely want to
see what evil lurks at $BB00. That area
of memory is normally reserved for the
denibblizing process when reading data
from a sector. It's scratch space,
essentially. It's overwritten every
time the disk reads itself (after boot1
is loaded).

But $BB00 isn't loaded yet, because I
interrupted the boot process before it
could be loaded. So now I need to trace
the boot again, but a little bit
further -- far enough for boot0 to load
boot1 (including the suspicious code at
$BB00), but no further.

My work disk has another program,
unimaginatively named AUTOTRACE1, which
does just that. It loads track 0,
sector 0, then patches the boot0 code
at $084A to call back to a routine
under my control (instead of jumping to
the original disk's boot1 code). The
only reason it didn't run already is
that the instruction at $084A is non-
standard. But the boot0 code is close
enough to standard that AUTOTRACE1
should be able to patch it. (I mean,
we *are* patching assembly language
code here. There's a very low tolerance
for error.)

]BRUN AUTOTRACE1
...reboots slot 6...
...reboots slot 5...
SAVING BOOT1
SAVING RWTS

Well, that worked flawlessly. Not only
did I get the rest of the boot1 code,
but the RWTS is apparently in as
standard location too. So before I
investigate the nibble check at $BB00,
I'm going to load that RWTS into
Advanced Demuffin to convert the disk
to a standard format.

Advanced Demuffin will only load RWTS
files from a drive in slot 6, which is
annoying since mine is in slot 5. Note
to self: patch that someday. In the
meantime, I'm swapping floppy disks
like some kind of 20th century peasant.

[S6,D1=my work disk]

]PR#6
]BRUN ADVANCED DEMUFFIN 1.1

--> LOAD NEW RWTS MODULE
    At $B8, load "RWTS"
    from drive 1

[S6,D1=original disk]
[S6,D2=blank disk]

--> FORMAT TARGET DISK

...grind grind grind...

--> CONVERT DISK

This disk is 16 sectors, and the
default options (copy the entire disk,
all tracks, all sectors) don't need to
be changed unless something goes
horribly wrong.

                 --v--

ADVANCED DEMUFFIN 1.1  - COPYRIGHT 1983
WRITTEN BY THE STACK -CORRUPT COMPUTING
=======PRESS ANY KEY TO CONTINUE=======
TRK:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
+R5:
    0123456789ABCDEF0123456789ABCDEF012
SC0:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SC1:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SC2:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SC3:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SC4:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SC5:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SC6:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SC7:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SC8:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SC9:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SCA:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SCB:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SCC:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SCD:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SCE:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
SCF:RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
=======================================
16 SC $00,$00 TO $22,$0F BY $01 TO DRV2

                 --^--

Those "R" flags? Read errors. Every
track, every sector. Remember when I
said the default options don't need to
be changed unless something goes
horribly wrong? (Seriously, I just said
that, like, a minute ago.) This is what
"horribly wrong" looks like. The RWTS
on this disk can't read... the disk.
Seriously, RWTS, you had one job...

Let's back up.

[S6,D1=my work disk]

]PR#5
...
]BLOAD BOOT1,A$2600
]CALL -151

; disconnect DOS
*FE89G FE93G

*B600<2600.2FFFM

*BB00L

; set reset vector
BB00-   A9 5D       LDA   #$5D
BB02-   8D F2 03    STA   $03F2
BB05-   A9 B7       LDA   #$B7
BB07-   EA          NOP
BB08-   8D F3 03    STA   $03F3
BB0B-   49 A5       EOR   #$A5
BB0D-   8D F4 03    STA   $03F4

; oh, this is probably important
BB10-   A9 AA       LDA   #$AA
BB12-   85 31       STA   $31

; relatively harmless initialization,
; then it jumps right back to $B700
BB14-   AD E9 B7    LDA   $B7E9
BB17-   4A          LSR
BB18-   4A          LSR
BB19-   4A          LSR
BB1A-   4A          LSR
BB1B-   09 C0       ORA   #$C0
BB1D-   8D 95 BA    STA   $BA95
BB20-   4C 00 B7    JMP   $B700

Hmm. I was sure that was going to be a
nibble check. But it's not. But I'm
guessing that it's still important,
although it's not obvious why. But I
think I've seen something like this on
other disks. Let me see if I'm right...

*B92FL

; check for epilogue bytes (part of the
; standard DOS 3.3 RWTS)
B92F-   BD 8C C0    LDA   $C08C,X
B932-   10 FB       BPL   $B92F
B934-   C9 DE       CMP   #$DE
B936-   D0 0A       BNE   $B942
B938-   EA          NOP
B939-   BD 8C C0    LDA   $C08C,X
B93C-   10 FB       BPL   $B939

; there it is!
B93E-   C5 31       CMP   $31
B940-   F0 5C       BEQ   $B99E
B942-   38          SEC
B943-   60          RTS

This RWTS is doing something sneaky to
make my job harder: it's putting one of
the epilogue bytes into a zero page
address, then reading the value from
there instead of using a constant.

Why? Because f--- you, that's why.
Because it makes the extracted RWTS
useless without initializing the magic
zero page location with the right magic
number. Automated RWTS extraction
programs wouldn't find this (as I just
saw when Advanced Demuffin failed to
read the original disk with the RWTS
from the original disk). Everything is
a countermeasure to something.

This calls for an IOB module. 

What's an IOB module? Well, the author
of Advanced Demuffin anticipated that
he couldn't anticipate everything, so
he made the program extensible. Quoting
from the Advanced Demuffin softdocs
(included on my work disk):

                 --v--

An IOB module is an interface for the
source RWTS. Advanced Demuffin uses the
IOB module to set up the IOB table and
jump to RWTS.  The IOB module is stored
from $1400-$14FB. When Advanced
Demuffin loads in a IOB module, it
reads the first sector of the file off
the track-sector list and stores it at
$13FC-$14FB. When Advanced Demuffin
wants to read a sector it JSRs to the
IOB module with the phase number,
sector number, and the page number
stored in the A, Y and X registers
respectively. Since the source drive
always has to be drive one, Advanced
Demuffin can make the IOB module very
compact. After it gets the page,track
and sector Advanced Demuffin sets up
the IOB for RWTS using this infor-
mation, and JMPs to RWTS. (It jumps
instead of JSRing, because it lets the
RWTS do the RTS.) Here is a list of the
IOB module that is built in to Advanced
Demuffin:

; Convert phase # to track #
1400-   4A          LSR

; Store track number
1401-   8D 22 0F    STA   $0F22

; Store sector number
1404-   8C 23 0F    STY   $0F23

; Store page number
; [note: original docs have incorrect
;        hex opcode on this line]
1407-   8E 27 0F    STX   $0F27

140A-   A9 01       LDA   #$01

; Store the drive number
140C-   8D 20 0F    STA   $0F20

; Store the read code
140F-   8D 2A 0F    STA   $0F2A

; With high byte of IOB
1412-   A9 0F       LDA   #$0F

; With low byte of IOB
1414-   A0 1E       LDY   #$1E

; Goto RWTS
1416-   4C 00 BD    JMP   $BD00

                 --^--

Basically, Advanced Demuffin only knows
how to call a custom RWTS if it

1. is loaded at $B800..$BFFF
2. uses a standard RWTS parameter table
3. has an entry point at $BD00 that
   takes the address of the parameter
   tables in A and Y
4. doesn't require initialization

As it turns out, that covers a *lot* of
copy protected disks, but it doesn't
cover this one because the RWTS relies
on the value of zero page $31.

So, let's make an IOB module.

]CALL -151

; Most of this is identical to the
; standard IOB module that comes with
; Advanced Demuffin (explained above).
1400-   4A          LSR
1401-   8D 22 0F    STA   $0F22
1404-   8C 23 0F    STY   $0F23
1407-   8E 27 0F    STX   $0F27
140A-   A9 01       LDA   #$01
140C-   8D 20 0F    STA   $0F20
140F-   8D 2A 0F    STA   $0F2A

; initialize the magic zero page value
1412-   A9 AA       LDA   #$AA
1414-   85 31       STA   $31

; get the address of the RWTS parameter
; table at $0F1E and call the RWTS
1416-   A9 0F       LDA   #$0F
1418-   A0 1E       LDY   #$1E
141A-   4C 00 BD    JMP   $BD00

*BSAVE IOB,A$1400,L$1D

Now let's tell Advanced Demuffin to use
this custom IOB as well as the RWTS we
captured from the original disk.

[S6,D1=my work disk]

]BRUN ADVANCED DEMUFFIN 1.1

--> LOAD NEW RWTS MODULE
    At $B8, load "RWTS"
    from D1

--> LOAD NEW IOB MODULE
    load "IOB"
    from D1

[S6,D1=original disk]
[S6,D2=blank disk]

--> CONVERT DISK

--> CHANGE DEFAULT VALUES? N

This disk is 16 sectors, and the
default options (copy the entire disk,
all tracks, all sectors) don't need to
be changed unless something goes
horribly wrong (again).

                 --v--

ADVANCED DEMUFFIN 1.1  - COPYRIGHT 1983
WRITTEN BY THE STACK -CORRUPT COMPUTING
=======PRESS ANY KEY TO CONTINUE=======
TRK:...................................
+.5:
    0123456789ABCDEF0123456789ABCDEF012
SC0:...................................
SC1:...................................
SC2:...................................
SC3:...................................
SC4:...................................
SC5:...................................
SC6:...................................
SC7:...................................
SC8:...................................
SC9:...................................
SCA:...................................
SCB:...................................
SCC:...................................
SCD:...................................
SCE:...................................
SCF:...................................
=======================================
16 SC $00,$00 TO $22,$0F BY $01 TO DRV2

                 --^--

Hooray! IOB saves the day!

[S6,D1=my work disk]
[S6,D2=fully demuffin'd copy]

]PR#6
...

]CATALOG,S6,D2

C1983 DSR^C#254
106 FREE

   El Mundo Hispanico

*A 002 HELLO
 A 013 HELLO.A
*B 002 HEATH LOGO UNPACK
*B 009 HEATH LOGO PACKED

*B 007 CAP 20.6.OBJ-T
*B 005 PANEL2.B
*B 002 TILES.B
*B 016 HRCG.SP
*B 006 UPPERCASE(B
*B 005 LOWERCASE(B
 A 028 MENU

 B 031 INTRO ART.B
*B 014 CREDITS.B
*B 002 STAR.S
*A 007 TITLE
*A 042 ACTIVITY2
 T 002 MAKE TEXT
 B 009 KIDSROOM.B
 B 009 DRESSPACO.B

 B 016 GRACIELA.B
 B 014 PACOWAKES.B
 B 028 BATHROOM.B
*A 033 ACTIVITY1
 B 010 BIGSINK.B
 B 002 RARROW-DOT.S
*A 047 ACT1QUIZ
*A 010 CONTINUE
*B 003 NUMBER(B

]RUN HELLO

The game loads and runs without
complaint. All further disk access is
done through standard DOS functions.
(It even runs from drive 2!) There
doesn't appear to be any kind of nibble
check or other copy protection, beyond
the custom DOS.

This is weird. I put the demuffin'd
copy in drive 1 and try booting
it... and it works! But I haven't
touched the RWTS; it's still the
original RWTS that expects a modified
address prologue on every other
track. So there's no way this RWTS can
read a disk that uses standard address
prologue on every track. How is that
possible?

Here's how: the original RWTS doesn't
actually check for a specific address
prologue. It does some bit math on the
first byte in the sequence and allows a
certain result.

[S6,D1=my work disk]

]PR#6
...

]BLOAD BOOT1,A$2600
]CALL -151

*FE89G FE93G

*B600<2600.2FFFM

*B94FL

; first byte does bit math (matches
; either "D4" or "D5")
B94F-   BD 8C C0    LDA   $C08C,X
B952-   10 FB       BPL   $B94F
B954-   4A          LSR
B955-   C9 6A       CMP   #$6A
B957-   D0 EF       BNE   $B948

; second byte is in zero page (grr)
B959-   BD 8C C0    LDA   $C08C,X
B95C-   10 FB       BPL   $B959
B95E-   C5 31       CMP   $31
B960-   D0 F2       BNE   $B954
B962-   A0 03       LDY   #$03

; third byte is just a constant
B964-   BD 8C C0    LDA   $C08C,X
B967-   10 FB       BPL   $B964
B969-   C9 96       CMP   #$96
B96B-   D0 E7       BNE   $B954

Disks 2 and 3 have no RWTS, but they
use the same modified disk structure as
disk 1, and the RWTS file I captured
from disk 1 also works to convert disks
2 and 3.

Quod erat liberandum.

                   ~

               Changelog


2024-10-06

- fixed data corruption on disk 2

2014-07-21

- initial release

---------------------------------------
A 4am crack                      No. 87
------------------EOF------------------
